#ifndef __DEBUG_H__
#define __DEBUG_H__

#include <stdio.h>


typedef enum {
    LEVEL_ERROR = 0,
    LEVEL_WARN  = 1,
    LEVEL_INFO  = 2,
    LEVEL_DEBUG = 3
} DebugLevel_e;


#ifndef DEBUG_LEVEL
#define DEBUG_LEVEL LEVEL_DEBUG
#endif

#define _debug_print_(level, file, line, ...) do {\
    if (level > DEBUG_LEVEL) break; \
    switch (level) { \
        case LEVEL_ERROR: \
            printf("\033[31m[ERROR]\033[0m %s : %d - ", file, line); break;\
        case LEVEL_WARN : \
            printf("\033[33m[WARN]\033[0m  %s : %d - ", file, line); break;\
        case LEVEL_INFO : \
            printf("\033[34m[INFO]\033[0m  %s : %d - ", file, line); break;\
        case LEVEL_DEBUG: \
            printf("\033[36m[DEBUG]\033[0m %s : %d - ", file, line); break;\
    }\
    printf(__VA_ARGS__); \
}while(0)


#ifdef DEBUG_MODE

#define PRINT_ERROR(...) _debug_print_(LEVEL_ERROR, __FILE__, __LINE__, __VA_ARGS__)
#define PRINT_WARN(...)  _debug_print_(LEVEL_WARN,  __FILE__, __LINE__, __VA_ARGS__)
#define PRINT_INFO(...)  _debug_print_(LEVEL_INFO,  __FILE__, __LINE__, __VA_ARGS__)
#define PRINT_DEBUG(...) _debug_print_(LEVEL_DEBUG, __FILE__, __LINE__, __VA_ARGS__)

#define BUG_ON(condition) do{if(condition){PRINT_ERROR(#condition);while(1);}}while(0)

#else   /* DEBUG_MODE */

#define PRINT_ERROR(...) ((void)0)
#define PRINT_WARN(...) ((void)0)
#define PRINT_INFO(...) ((void)0)
#define PRINT_DEBUG(...) ((void)0)

#define BUG_ON(condition) ((void)0)

#endif  /* DEBUG_MODE */


#endif /* __DEBUG_H__ */
